import sys
import mysql.connector
from mysql.connector import Error
from PyQt5.QtWidgets import (
    QApplication, QMainWindow, QWidget, QVBoxLayout, QHBoxLayout,
    QLabel, QPushButton, QLineEdit, QMessageBox, QGroupBox,
    QFormLayout, QTextEdit, QDialog, QDialogButtonBox
)
from PyQt5.QtGui import QFont
import traceback


class DBUtils:
    """数据库工具类（完整版）"""

    def __init__(self):
        self.connection = None
        self._connect()

    def _connect(self):
        """建立数据库连接"""
        try:
            self.connection = mysql.connector.connect(
                host='localhost',
                database='bank system',
                user='root',
                password='1234',
                autocommit=True
            )
            if self.connection.is_connected():
                print(f"成功连接到MySQL服务器 (版本 {self.connection.server_info})")
        except Error as e:
            print(f"数据库连接失败: {e}")
            raise ConnectionError(f"无法连接数据库:\n{str(e)}\n请检查数据库服务是否启动")

    def __del__(self):
        self.disconnect()

    def disconnect(self):
        """安全关闭连接"""
        if self.connection and self.connection.is_connected():
            try:
                self.connection.close()
                print("数据库连接已关闭")
            except Error as e:
                print(f"关闭连接时出错: {e}")

    def execute_query(self, query, params=None, fetch=True):
        """执行SQL查询"""
        cursor = None
        try:
            if not self.connection or not self.connection.is_connected():
                self._connect()

            cursor = self.connection.cursor(dictionary=True)
            cursor.execute(query, params or ())

            if fetch:
                result = cursor.fetchall()
                return result if result else []
            else:
                return True

        except Error as e:
            print(f"查询执行失败: {e}")
            return None
        finally:
            if cursor:
                cursor.close()


class CustomerManager:
    """客户管理类（完整版）"""

    def __init__(self, db_utils):
        self.db = db_utils

    def report_loss(self, card_id, is_loss=True):
        """挂失/解挂银行卡"""
        try:
            # 检查当前状态
            check_query = "SELECT IsReportLoss FROM cardInfo WHERE cardID = %s"
            result = self.db.execute_query(check_query, (card_id,))

            if not result:
                return False, "银行卡不存在"

            current_status = result[0]['IsReportLoss']

            target_status = "是" if is_loss else "否"
            if current_status == target_status:
                status = "已挂失" if is_loss else "正常"
                return False, f"银行卡当前已是{status}状态"

            # 更新状态
            update_query = "UPDATE cardInfo SET IsReportLoss = %s WHERE cardID = %s"
            success = self.db.execute_query(update_query, (target_status, card_id), False)

            if success:
                action = "挂失" if is_loss else "解挂"
                return True, f"银行卡{action}成功"
            return False, "操作失败，未更新任何记录"

        except Exception as e:
            traceback.print_exc()
            return False, f"{'挂失' if is_loss else '解挂'}失败: {str(e)}"

    def verify_identity(self, card_id, name, pid):
        """验证身份信息"""
        query = """
        SELECT COUNT(*) AS valid 
        FROM cardInfo a 
        JOIN userInfo b ON a.customerID = b.customerID 
        WHERE a.cardID = %s AND b.customerName = %s AND b.pid = %s
        """
        try:
            result = self.db.execute_query(query, (card_id, name, pid))
            return result and result[0]['valid'] > 0
        except Exception as e:
            traceback.print_exc()
            return False


class CustomerLoginWindow(QWidget):
    """登录窗口（完整版）"""

    def __init__(self):
        super().__init__()
        self.setWindowTitle("银行卡客户登录")
        self.setFixedSize(400, 250)
        self.setup_ui()

    def setup_ui(self):
        """初始化登录界面"""
        layout = QVBoxLayout()
        layout.setSpacing(15)
        layout.setContentsMargins(30, 30, 30, 30)

        # 登录表单
        form_group = QGroupBox("银行卡登录")
        form_layout = QFormLayout()

        self.card_input = QLineEdit()
        self.card_input.setPlaceholderText("请输入16位银行卡号")
        self.card_input.setMaxLength(16)

        self.pwd_input = QLineEdit()
        self.pwd_input.setPlaceholderText("请输入6位密码")
        self.pwd_input.setMaxLength(6)
        self.pwd_input.setEchoMode(QLineEdit.Password)

        form_layout.addRow("卡号:", self.card_input)
        form_layout.addRow("密码:", self.pwd_input)
        form_group.setLayout(form_layout)

        # 登录按钮
        login_btn = QPushButton("登录")
        login_btn.clicked.connect(self.handle_login)

        # 布局
        layout.addWidget(form_group)
        layout.addWidget(login_btn)
        self.setLayout(layout)

    def handle_login(self):
        """处理登录逻辑"""
        card_id = self.card_input.text().strip()
        password = self.pwd_input.text().strip()

        # 输入验证
        if len(card_id) != 16 or not card_id.isdigit():
            QMessageBox.warning(self, "错误", "卡号必须为16位数字")
            return

        if len(password) != 6 or not password.isdigit():
            QMessageBox.warning(self, "错误", "密码必须为6位数字")
            return

        # 初始化数据库连接
        try:
            db = DBUtils()
        except ConnectionError as e:
            QMessageBox.critical(self, "数据库错误", str(e))
            return

        # 验证登录
        try:
            query = """
            SELECT cardID, customerID, balance, IsReportLoss 
            FROM cardInfo 
            WHERE cardID = %s AND pass = %s
            """
            result = db.execute_query(query, (card_id, password))

            if not result:
                QMessageBox.warning(self, "登录失败", "卡号或密码错误")
                db.disconnect()
                return

            card_info = result[0]

            # 登录成功，打开主界面
            self.main_window = ReportLossWindow(
                card_info['cardID'],
                card_info['customerID'],
                card_info['balance'],
                db,
                card_info['IsReportLoss'] == '是'
            )
            self.hide()
            self.main_window.show()

        except Exception as e:
            QMessageBox.critical(self, "错误", f"登录时发生错误:\n{str(e)}")
            traceback.print_exc()
            db.disconnect()


class ReportLossWindow(QMainWindow):
    """主操作窗口（完整版，包含logout方法）"""

    def __init__(self, card_id, customer_id, balance, db_utils, is_lost=False):
        super().__init__()
        self.card_id = card_id
        self.customer_id = customer_id
        self.balance = balance
        self.db = db_utils
        self.customer = CustomerManager(db_utils)
        self.is_lost = is_lost  # 记录卡片是否已挂失

        self.setWindowTitle(f"银行卡服务 - 卡号: {card_id}")
        self.setFixedSize(1100, 800)
        self.setup_ui()

    def setup_ui(self):
        """初始化主界面"""
        central_widget = QWidget()
        self.setCentralWidget(central_widget)

        layout = QVBoxLayout(central_widget)
        layout.setSpacing(15)
        layout.setContentsMargins(20, 20, 20, 20)

        # 账户信息
        info_group = QGroupBox("账户信息")
        info_layout = QFormLayout()

        self.balance_label = QLabel(f"¥ {self.balance:.2f}")
        self.balance_label.setStyleSheet("font-size: 18px; font-weight: bold;")

        self.status_label = QLabel("已挂失" if self.is_lost else "正常")

        info_layout.addRow("卡号:", QLabel(self.card_id))
        info_layout.addRow("客户ID:", QLabel(str(self.customer_id)))
        info_layout.addRow("当前余额:", self.balance_label)
        info_layout.addRow("状态:", self.status_label)
        info_group.setLayout(info_layout)

        # 业务操作
        btn_group = QGroupBox("银行卡服务")
        btn_layout = QVBoxLayout()

        self.loss_btn = QPushButton("申请挂失")
        self.unloss_btn = QPushButton("申请解挂")
        self.logout_btn = QPushButton("退出登录")

        # 根据当前状态设置按钮可用性
        self.loss_btn.setEnabled(not self.is_lost)
        self.unloss_btn.setEnabled(self.is_lost)

        self.loss_btn.clicked.connect(lambda: self.show_loss_dialog(True))
        self.unloss_btn.clicked.connect(lambda: self.show_loss_dialog(False))
        self.logout_btn.clicked.connect(self.logout)  # 连接到logout方法

        btn_layout.addWidget(self.loss_btn)
        btn_layout.addWidget(self.unloss_btn)
        btn_layout.addStretch()
        btn_layout.addWidget(self.logout_btn)
        btn_group.setLayout(btn_layout)

        # 操作记录
        self.log_display = QTextEdit()
        self.log_display.setReadOnly(True)
        self.log_display.setMinimumHeight(150)

        # 布局
        layout.addWidget(info_group)
        layout.addWidget(btn_group)
        layout.addWidget(QLabel("操作记录:"))
        layout.addWidget(self.log_display)

    def show_loss_dialog(self, is_loss):
        """显示挂失/解挂对话框"""
        dialog = QDialog(self)
        title = "银行卡挂失" if is_loss else "银行卡解挂"
        dialog.setWindowTitle(title)
        dialog.setFixedSize(500, 300)

        layout = QVBoxLayout()

        # 表单控件
        name_label = QLabel("持卡人姓名:")
        name_input = QLineEdit()
        name_input.setPlaceholderText("请输入持卡人姓名")

        pid_label = QLabel("身份证号:")
        pid_input = QLineEdit()
        pid_input.setPlaceholderText("请输入身份证号")

        # 操作说明
        action = "挂失" if is_loss else "解挂"
        info_label = QLabel(f"<b>正在进行银行卡{action}操作</b><br>请输入完整的身份信息进行验证")
        info_label.setStyleSheet("color: #444; padding: 10px;")

        # 按钮
        btn_box = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel)
        btn_box.accepted.connect(lambda: self.handle_loss(
            dialog, is_loss, name_input.text(), pid_input.text()
        ))
        btn_box.rejected.connect(dialog.reject)

        # 布局
        form = QFormLayout()
        form.addRow(name_label, name_input)
        form.addRow(pid_label, pid_input)

        layout.addWidget(info_label)
        layout.addLayout(form)
        layout.addWidget(btn_box)
        dialog.setLayout(layout)

        dialog.exec_()

    def handle_loss(self, dialog, is_loss, name, pid):
        """处理挂失/解挂请求"""
        name = name.strip()
        pid = pid.strip()

        if not name or not pid:
            QMessageBox.warning(self, "错误", "姓名和身份证号不能为空")
            return

        # 验证身份
        if not self.customer.verify_identity(self.card_id, name, pid):
            QMessageBox.warning(self, "验证失败", "身份信息不匹配")
            self.log_display.append(f"[操作失败] 身份验证失败")
            return

        # 执行操作
        action = "挂失" if is_loss else "解挂"
        success, msg = self.customer.report_loss(self.card_id, is_loss)

        if success:
            # 更新UI状态
            self.is_lost = is_loss
            self.status_label.setText("已挂失" if self.is_lost else "正常")
            self.loss_btn.setEnabled(not self.is_lost)
            self.unloss_btn.setEnabled(self.is_lost)

            self.log_display.append(f"[{action}成功] {msg}")
            dialog.accept()
            QMessageBox.information(self, "成功", msg)
        else:
            QMessageBox.warning(self, "失败", msg)
            self.log_display.append(f"[{action}失败] {msg}")

    def logout(self):
        """退出登录方法 - 修复点"""
        # 关闭数据库连接
        if self.db:
            self.db.disconnect()

        # 返回登录窗口
        login_window = CustomerLoginWindow()
        login_window.show()

        # 关闭当前窗口
        self.close()


if __name__ == "__main__":
    app = QApplication(sys.argv)

    # 设置全局字体
    font = QFont()
    font.setFamily("Microsoft YaHei" if sys.platform == 'win32' else "Arial")
    font.setPointSize(10)
    app.setFont(font)

    try:
        window = CustomerLoginWindow()
        window.show()
        sys.exit(app.exec_())

    except Exception as e:
        QMessageBox.critical(None, "启动失败", f"程序初始化失败:\n{str(e)}")
        traceback.print_exc()
        sys.exit(1)